package view.trajectory;

import java.util.ArrayList;
import javax.media.opengl.GL;

import mathematics.PolylineOrientation;
import mathematics.geometry.BezierCurve;
import mathematics.geometry.DiskGeometry;
import mathematics.geometry.PolylineGeometry;
import matrix.GraphDoor;
import matrix.GraphNode;
import model.DoorModel;
import model.RoomModel;
import model.trajectory.TransitionTrajectoryModel;

import settings.Settings;
import utils.Point3D;
import utils.TimeIntervalle;
import view.DoorView;
import view.RoomView;

public class TransitionTrajectoryView extends BaseTrajectoryView
{
	public TimeIntervalle intervalle;
	
	public RoomView firstRoom;
	public RoomView secondRoom;
	public DoorView door;
	
	public PolylineOrientation orientation;
	
	float computedOffset = 0;
	
	public TransitionTrajectoryView(GL gl, TransitionTrajectoryModel model, DoorView door, RoomView firstRoom, RoomView secondRoom)
	{
		super(model);
		this.door = door;
		this.intervalle = model.intervalle;
		this.setGeometry(new PolylineGeometry());
		
		if(model.reverse)
		{
			this.firstRoom = secondRoom;
			this.secondRoom = firstRoom;
			this.orientation = PolylineOrientation.Left;
		}
		else
		{
			this.firstRoom = firstRoom;
			this.secondRoom = secondRoom;
			this.orientation = PolylineOrientation.Right;
		}
	}

	
	public boolean mustDraw() 
	{
		return true; //(!this.firstRoom.isExpendedShape() || !this.secondRoom.isExpendedShape());
	}

	@Override
	public void update(long time, long beginTime, long endTime)
	{		
		getGeometry().clear();
		TimeIntervalle timeSpan = new TimeIntervalle(beginTime, endTime);
		TransitionTrajectoryModel model = (TransitionTrajectoryModel)this.getModel();
		if( !timeSpan.include(model.intervalle.beginTime) && !timeSpan.include(model.intervalle.endTime))
		{
			return;
		}
		
		float offset;
		if(model.reverse)
		{
			offset = ++this.door.currentReverseIndex;
		}
		else
		{
			offset = ++this.door.currentIndex;
		}

		if(this.firstRoom.isExpendedShape() && this.secondRoom.isExpendedShape())
		{
			this.getGeometry().add(this.getLastSubtrajectory().getGeometry().get(this.getLastSubtrajectory().getGeometry().size()-1));
			this.getGeometry().add(((DoorModel)this.door.getModel()).AnchoragePoint);
		}
		else if(Settings.isStraightDoorLinks())
		{
			ArrayList<Point3D> positions = model.toPoint3DList();
			if(this.firstRoom.isNodeShape() && this.secondRoom.isNodeShape())
			{
				this.getGeometry().add(Point3D.sum(((RoomModel)firstRoom.getModel()).getCenter(), Point3D.sum(firstRoom.getModel().getPosition(), positions.get(0))));
				this.getGeometry().add(Point3D.sum(((RoomModel)secondRoom.getModel()).getCenter(), Point3D.sum(secondRoom.getModel().getPosition(), positions.get(2))));
			}
			else if (this.firstRoom.isNodeShape())
			{
				this.getGeometry().add(Point3D.sum(((RoomModel)firstRoom.getModel()).getCenter(), Point3D.sum(firstRoom.getModel().getPosition(), positions.get(0))));
				this.getGeometry().add(Point3D.sum(secondRoom.getModel().getPosition(), positions.get(1)));
			}
			else 
			{
				this.getGeometry().add(Point3D.sum(firstRoom.getModel().getPosition(), positions.get(1)));
				this.getGeometry().add(Point3D.sum(((RoomModel)secondRoom.getModel()).getCenter(), Point3D.sum(secondRoom.getModel().getPosition(), positions.get(2))));
			}	
		}
		else if(Settings.isPolylineLinks())
		{			
			GraphDoor firstRoomGraphDoor = ((RoomModel)this.firstRoom.getModel()).getMatrix().getDoorNode(model.door);
			GraphNode firstRoomNextGraphNode = (GraphNode) ((RoomModel)this.firstRoom.getModel()).getMatrix().getNeighbours(firstRoomGraphDoor).get(0);	
		
			GraphDoor secondRoomGraphDoor = ((RoomModel)this.secondRoom.getModel()).getMatrix().getDoorNode(model.door);
			GraphNode secondRoomNextGraphNode = (GraphNode) ((RoomModel)this.secondRoom.getModel()).getMatrix().getNeighbours(secondRoomGraphDoor).get(0);

			if(!this.firstRoom.isExpendedShape())
			{
				getGeometry().add(Point3D.sum(((RoomModel)firstRoom.getModel()).getCenter(), firstRoom.getModel().getPosition()));
				getGeometry().add(Point3D.sum(((RoomModel)firstRoom.getModel()).getPosition(), firstRoomNextGraphNode.getPosition()));
			}
			else
			{
				getGeometry().add(Point3D.sum(((RoomModel)firstRoom.getModel()).getPosition(), firstRoomGraphDoor.getPosition()));		
			}
			if(!this.secondRoom.isExpendedShape())
			{				
				getGeometry().add(Point3D.sum(((RoomModel)secondRoom.getModel()).getPosition(), secondRoomNextGraphNode.getPosition()));
				getGeometry().add(Point3D.sum(((RoomModel)secondRoom.getModel()).getCenter(), secondRoom.getModel().getPosition()));
			}	
			else
			{
				getGeometry().add(Point3D.sum(((RoomModel)secondRoom.getModel()).getPosition(), secondRoomGraphDoor.getPosition()));
			}	
		}
		else if(Settings.isBezierLinks())
		{
			Point3D p0;
			Point3D p1;
			Point3D p2;
			Point3D p3;
			
			GraphDoor firstRoomGraphDoor = ((RoomModel)this.firstRoom.getModel()).getMatrix().getDoorNode(model.door);
			GraphNode firstRoomNextGraphNode = (GraphNode) ((RoomModel)this.firstRoom.getModel()).getMatrix().getNeighbours(firstRoomGraphDoor).get(0);	
		
			GraphDoor secondRoomGraphDoor = ((RoomModel)this.secondRoom.getModel()).getMatrix().getDoorNode(model.door);
			GraphNode secondRoomNextGraphNode = (GraphNode) ((RoomModel)this.secondRoom.getModel()).getMatrix().getNeighbours(secondRoomGraphDoor).get(0);

			if(this.firstRoom.isNodeShape() )
			{
				p0 = Point3D.sum(((RoomModel) this.firstRoom.getModel()).getCenter(), this.firstRoom.getModel().getPosition());		
				p1 = Point3D.sum(firstRoomNextGraphNode.getPosition(), this.firstRoom.getModel().getPosition());
			}
			else
			{
				p0 = Point3D.sum(firstRoomGraphDoor.getDoorModel().AnchoragePoint, this.firstRoom.getModel().getPosition());
				p1 = secondRoomNextGraphNode.getPosition();
			}
		
				
			if(this.secondRoom.isNodeShape() )
			{
				p3 = Point3D.sum(((RoomModel) this.secondRoom.getModel()).getCenter(), this.secondRoom.getModel().getPosition());
				
				p2 = secondRoomNextGraphNode.getPosition();
				//p3 = this.secondRoom.getModel().getPosition();
			}
			else
			{
				p2 = firstRoomNextGraphNode.getPosition();
				p3 = secondRoomGraphDoor.getDoorModel().AnchoragePoint;
			}
			
			this.setGeometry(new BezierCurve(p0, p1, p2, p3, (float)Settings.BezierWeightFactor, 20));	
		}
		
		double firstRoomOffset = this.firstRoom.getTotalMaxOffset() / 2.0f;
		if(firstRoomOffset < Settings.NodeTrajectoryOffset)
		{
			firstRoomOffset = Settings.NodeTrajectoryOffset;
		}
		firstRoomOffset *= ( (this.firstRoom.getIndexOfSubtrajectory(this.getLastSubtrajectory(), time, beginTime, endTime) ) + 1);
		firstRoomOffset += (long) (this.firstRoom.nodeSize / 2.0f);
	
		double secondRoomOffset = this.secondRoom.getTotalMaxOffset() / 2.0f;
		if(secondRoomOffset < Settings.NodeTrajectoryOffset)
		{
			secondRoomOffset = Settings.NodeTrajectoryOffset;
		}
		secondRoomOffset *= ((this.secondRoom.getIndexOfSubtrajectory(this.getNextSubtrajectory() , time, beginTime, endTime)) + 1);
		secondRoomOffset += (long) (this.secondRoom.nodeSize / 2.0f);
		
		
		float lineOffset = Settings.NodeTrajectoryOffset / 2.0f *  offset;
		DiskGeometry firstRoomDisk = new DiskGeometry(Point3D.sum(((RoomModel)firstRoom.getModel()).getCenter(), firstRoom.getModel().getPosition()),  (float) firstRoomOffset);
		DiskGeometry secondRoomDisk = new DiskGeometry(Point3D.sum(((RoomModel)secondRoom.getModel()).getCenter(), secondRoom.getModel().getPosition()),  (float) secondRoomOffset);
		
		getGeometry().offset(lineOffset);
		
		if(firstRoom.isNodeShape())
		{
			getGeometry().clip(firstRoomDisk);
		}
		if(secondRoom.isNodeShape())
		{
			getGeometry().clip(secondRoomDisk);
		}
		
		if(this.getLastSubtrajectory() != null)
		{
			this.getLastSubtrajectory().update(time, beginTime, endTime);
		}
	}


	@Override
	public void update() {
		// TODO Auto-generated method stub
		
	}
}
